package ar.edu.itba.it.cg.grupo01.impl.shape.light;

import java.awt.Color;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import javax.vecmath.Point2f;
import javax.vecmath.Point3f;
import javax.vecmath.Vector3f;

import ar.edu.itba.it.cg.grupo01.api.Intersection;
import ar.edu.itba.it.cg.grupo01.api.Ray;
import ar.edu.itba.it.cg.grupo01.api.shape.Shape;
import ar.edu.itba.it.cg.grupo01.api.shape.light.Light;
import ar.edu.itba.it.cg.grupo01.impl.IntersectionFactory;
import ar.edu.itba.it.cg.grupo01.impl.Precision;
import ar.edu.itba.it.cg.grupo01.impl.shape.AABB;
import ar.edu.itba.it.cg.grupo01.impl.shape.AbstractShape;

public class PointLight extends AbstractShape implements Light {

	private static final float FACTOR = 7;
	private Point3f lightPoint;
	private float power;
	private Color lightColor;

	public PointLight(Point3f lightPoint,
			IntersectionFactory intersectionFactory, Color color, float power) {
		super(intersectionFactory);
		this.lightColor = color;
		this.lightPoint = lightPoint;
		this.power = power;
	}

	@Override
	public boolean containedInAABB(AABB box) {
		return box.contains(lightPoint);
	}

	@Override
	public Point3f getMaxXYZ() {
		return (Point3f) lightPoint.clone();
	}

	@Override
	public Point3f getMinXYZ() {
		return (Point3f) lightPoint.clone();
	}

	@Override
	public Vector3f getNormal(Point3f point) {
		Vector3f normal = new Vector3f(lightPoint);
		normal.sub(point);
		normal.normalize();
		return normal;
	}

	@Override
	public Shape getTransformedShape() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Collection<Point3f> getVertices() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Intersection<? extends Shape> intersects(Ray ray) {

		Vector3f rayLightDir = new Vector3f(lightPoint);
		rayLightDir.sub(ray.getOrigin());
		rayLightDir.normalize();

		if (!ray.getDirection().epsilonEquals(rayLightDir, Precision.EPSILON)) {
			return intersectionFactory.emptyIntersection();
		} else {
			return intersectionFactory.createIntersection(lightPoint, this,
					Intersection.Type.OUT);
		}
	}

	@Override
	public boolean isLight() {
		return true;
	}

	@Override
	public Point2f getUVCoordinates(Point3f point) {
		throw new UnsupportedOperationException("I am a light!");
	}

	@Override
	public Point3f getSource() {
		return (Point3f) lightPoint.clone();
	}

	public void setPower(float power) {
		this.power = power;
	}

	@Override
	public float getPower() {
		return power;
	}

	@Override
	public float getAttenuation(Point3f point) {

		// Lights with power > 1000 have infinite reach
		if (power > 1000) {
			return 1.0f;
		}

		float lightDistance = point.distance(lightPoint);
		float factorLight = (1 / power) * FACTOR;
		float attenuation = 1 / (lightDistance * (factorLight + factorLight
				* lightDistance));
		return attenuation > 1.0f ? 1.0f : attenuation;

		// float distanceToLight = point.distance(lightPoint);
		// float attenuation = 1 / (1.0 + 0.014 * distanceToLight + 0.0007
		// * distanceToLight * distanceToLight);
		// return attenuation;
	}

	@Override
	public Color getColor() {
		return lightColor;
	}

	@Override
	public void setColor(Color color) {
		this.lightColor = color;
	}

	@Override
	public List<Vector3f> getLigthDirs(Point3f intersectionPoint) {
		List<Vector3f> dirs = new ArrayList<Vector3f>();
		dirs.add(getNormal(intersectionPoint));
		return dirs;
	}

	@Override
	public Point3f getUVWCoordinates(Point3f point) {
		throw new UnsupportedOperationException("I am a light!");
	}

}
